pub(crate) mod app {
    use super::child::*;
    use quic_rpc_macros::service;
    use quic_rpc_utils::StreamExt;
    use std::sync::Arc;

    #[derive(Clone, Default)]
    pub(crate) struct AppService(Arc<ChildService>);

    // 仅生成服务端实现
    #[cfg_attr(
        all(feature = "server", not(feature = "client")),
        service(server = true, public = crate, ChildService = 0)
    )]
    // 仅生成客户端实现
    #[cfg_attr(
        all(feature = "client", not(feature = "server")),
        service(client = true, public = crate, ChildService = 0)
    )]
    // 同时生成服务端和客户端实现
    #[cfg_attr(
        all(feature = "server", feature = "client"),
        service(server = true, client = true, public = crate, ChildService = 0)
    )]
    // 不生成服务端和客户端实现，仅生成传输的数据结构
    #[cfg_attr(
        not(any(feature = "server", feature = "client")),
        service(public = crate, ChildService = 0)
    )]
    impl AppService {
        /// 获取应用版本
        async fn app_version(&self) -> String {
            env!("CARGO_PKG_VERSION").to_string()
        }

        /// 加法计算，演示一对一请求和响应
        async fn add(&self, a: i32, b: i64) -> i128 {
            (a as i64 + b).into()
        }

        /// 算数求和，演示客户端流模式
        async fn sum(&self, context: u8, items: impl quic_rpc_utils::Stream<Item = i64>) -> i64 {
            dbg!(context);
            let mut sum = 0i64;
            quic_rpc_utils::pin!(items);
            while let Some(n) = items.next().await {
                dbg!(&n);
                sum += n;
            }
            println!("Sum done.");
            sum
        }

        /// 倒计时，演示服务端流模式
        async fn countdown(
            &self,
            duration: i16,
            tip: String,
        ) -> impl quic_rpc_utils::Stream<Item = i32> {
            println!("{}", tip);
            async_stream::stream! {
                for i in (0..duration).rev() {
                    tokio::time::sleep(std::time::Duration::from_millis(1000)).await;
                    yield i as i32;
                }
            }
        }
    }
}

mod child {
    use quic_rpc_macros::service;
    use quic_rpc_utils::StreamExt;

    #[derive(Clone, Default)]
    pub(crate) struct ChildService;

    // 仅生成服务端实现
    #[cfg_attr(
        all(feature = "server", not(feature = "client")),
        service(server = true, public = crate)
    )]
    // 仅生成客户端实现
    #[cfg_attr(
        all(feature = "client", not(feature = "server")),
        service(client = true, public = crate)
    )]
    // 同时生成服务端和客户端实现
    #[cfg_attr(
        all(feature = "server", feature = "client"),
        service(server = true, client = true, public = crate)
    )]
    // 不生成服务端和客户端实现，仅生成传输的数据结构
    #[cfg_attr(
        not(any(feature = "server", feature = "client")),
        service(public = crate)
    )]
    impl ChildService {
        // hello，演示子服务申明和调用
        async fn hello(&self, name: String) {
            println!("Hello {}.", name);
        }

        /// 回显字符串，演示双向流模式
        async fn echo(
            &self,
            name: String,
            flag: u8,
            sender: impl quic_rpc_utils::Stream<Item = u8>,
        ) -> impl quic_rpc_utils::Stream<Item = String> {
            async_stream::stream! {
                quic_rpc_utils::pin!(sender);
                while let Some(item) = sender.next().await {
                    yield format!("Echo {}, {}", name, item + flag)
                }
            }
        }
    }
}

mod empty {
    use quic_rpc_macros::service;

    #[derive(Clone)]
    pub(crate) struct EmptyService;

    // 仅生成服务端实现
    #[cfg_attr(
        all(feature = "server", not(feature = "client")),
        service(server = true, public = crate)
    )]
    // 仅生成客户端实现
    #[cfg_attr(
        all(feature = "client", not(feature = "server")),
        service(client = true, public = crate)
    )]
    // 同时生成服务端和客户端实现
    #[cfg_attr(
        all(feature = "server", feature = "client"),
        service(server = true, client = true, public = crate)
    )]
    // 不生成服务端和客户端实现，仅生成传输的数据结构
    #[cfg_attr(
        not(any(feature = "server", feature = "client")),
        service(public = crate)
    )]
    impl EmptyService {}
}
